import { Component, createRef } from 'preact';
import interact from 'interactjs';
import { Namespace } from '../../utils';
import { ChatMessages } from '../chat-messages/chat-messages';
import { ChatInput } from '../chat-input/chat-input';
import { AiChatController, AiTopicController } from '../../controller';
import {
  AISvg,
  CloseSvg,
  MinimizeSvg,
  FullScreenSvg,
  CloseFullScreenSvg,
} from '../../icons';
import { AIChatConst } from '../../constants';
import { IChatToolbarItem } from '../../interface';
import { ChatTopics } from '../chat-topics/chat-topics';
import { ChatToolbar } from '../chat-toolbar/chat-toolbar';
import './chat-container.scss';

export interface ChatContainerProps {
  /**
   * 呈现模式
   *
   * @author tony001
   * @date 2025-02-23 16:02:00
   * @type {('DEFAULT' | 'TOPIC')}
   */
  mode: 'DEFAULT' | 'TOPIC';
  /**
   * ai话题控制器
   *
   * @author tony001
   * @date 2025-02-23 16:02:38
   * @type {AiTopicController}
   */
  aiTopic: AiTopicController;
  /**
   * 聊天控制器
   *
   * @author tony001
   * @date 2025-02-23 16:02:24
   * @type {AiChatController}
   */
  aiChat: AiChatController;
  /**
   * 关闭聊天窗口
   *
   * @author chitanda
   * @date 2023-10-15 19:10:35
   */
  close: () => void;

  /**
   * 全屏行为
   *
   * @memberof ChatContainerProps
   */
  fullscreen: (target: boolean) => void;

  /**
   * 最小化行为
   *
   * @memberof ChatContainerProps
   */
  minimize: (target: boolean) => void;

  /**
   * 标题
   *
   * @type {string}
   * @memberof ChatContainerProps
   */
  caption?: string;

  /**
   * 内容工具项
   *
   * @type {IChatToolbarItem[]}
   * @memberof ChatContainerProps
   */
  contentToolbarItems?: IChatToolbarItem[];

  /**
   * 底部工具项
   *
   * @type {IChatToolbarItem[]}
   * @memberof ChatContainerProps
   */
  footerToolbarItems?: IChatToolbarItem[];
}

interface ChatContainerState {
  /**
   * 全屏状态
   *
   * @author ljx
   * @date 2024-05-07 15:10:31
   */
  isFullScreen: boolean;

  /**
   * 最小化
   *
   * @type {boolean}
   * @memberof ChatContainerState
   */
  isMinimize: boolean;
}

/**
 * 聊天窗口容器，可拖拽，可缩放
 *
 * @author chitanda
 * @date 2023-10-13 17:10:37
 * @export
 * @class ChatContainer
 * @extends {Component<ChatContainerProps>}
 */
export class ChatContainer extends Component<
  ChatContainerProps,
  ChatContainerState
> {
  constructor(props: ChatContainerProps | undefined) {
    super(props);
    // 初始化状态
    this.state = {
      isFullScreen: false,
      isMinimize: false,
    };
  }

  ns = new Namespace('chat-container');

  containerRef = createRef<HTMLDivElement>();

  dragHandle = createRef<HTMLDivElement>();

  minimizeRef = createRef<HTMLDivElement>();

  data = {
    x: window.innerWidth - 600,
    y: 0,
    width: 600,
    height: window.innerHeight,
    minWidth: 300,
    minHeight: 300,
  };

  minimizeData = {
    x: window.innerWidth - 86,
    y: window.innerHeight - 86,
  };

  /**
   * 是否禁止拖动
   * - 拖拽边时应禁止拖动
   * @type {boolean}
   * @memberof ChatContainer
   */
  disabled: boolean = false;

  /**
   * 最小化是否在拖拽中
   * - 在拖拽时不应触发点击事件
   * @type {boolean}
   * @memberof ChatContainer
   */
  isDragging: boolean = false;

  calcWindowStyle() {
    return {
      left: `${this.data.x}px`,
      top: `${this.data.y}px`,
      height: `${this.data.height}px`,
      width: `${this.data.width}px`,
      'z-index': '1000',
    };
  }

  calcMinimizeStyle() {
    return {
      left: `${this.minimizeData.x}px`,
      top: `${this.minimizeData.y}px`,
      'z-index': '99999',
    };
  }

  setStyle() {
    Object.assign(this.containerRef.current!.style, this.calcWindowStyle());
    Object.assign(this.minimizeRef.current!.style, this.calcMinimizeStyle());
  }

  componentDidMount(): void {
    const minimizeCache = localStorage.getItem(
      AIChatConst.MINIMIZE_STYLY_CHCHE,
    );
    if (minimizeCache) {
      this.minimizeData = JSON.parse(minimizeCache);
    }
    const cache = localStorage.getItem(AIChatConst.STYLE_CACHE);
    if (cache) {
      this.data = JSON.parse(cache);
      // 保持在窗口内部
      if (this.data.x > window.innerWidth) {
        this.data.x = window.innerWidth - 100;
      }
      if (this.data.y > window.innerHeight) {
        this.data.y = window.innerHeight - 100;
      }
    }
    this.setStyle();
    const state = this.data;
    // 注册最小化拖拽
    this.minimizeRef.current!.onmousedown = (e: MouseEvent): void => {
      // 禁止选择文本，避免拖动时出现选择效果
      document.body.style.userSelect = 'none';
      const offsetX = e.clientX - this.minimizeRef.current!.offsetLeft;
      const offsetY = e.clientY - this.minimizeRef.current!.offsetTop;
      const start = Date.now();
      const onMouseMove = (evt: MouseEvent): void => {
        this.minimizeData.x = evt.clientX - offsetX;
        this.minimizeData.y = evt.clientY - offsetY;
        this.setStyle();
      };
      const onMouseUp = (): void => {
        // 恢复选择文本功能
        const end = Date.now();
        // 鼠标按下到抬起的时间超过300毫秒则认定为拖拽中
        this.isDragging = end - start > 300;
        document.body.style.userSelect = '';
        document.removeEventListener('mousemove', onMouseMove);
        document.removeEventListener('mouseup', onMouseUp);
      };

      document.addEventListener('mousemove', onMouseMove);
      document.addEventListener('mouseup', onMouseUp);
    };
    // 注册窗口拖拽
    this.dragHandle.current!.onmousedown = (e: MouseEvent): void => {
      if (this.disabled || this.state.isFullScreen) return;
      // 禁止选择文本，避免拖动时出现选择效果
      document.body.style.userSelect = 'none';
      const offsetX = e.clientX - this.containerRef.current!.offsetLeft;
      const offsetY = e.clientY - this.containerRef.current!.offsetTop;
      const onMouseMove = (evt: MouseEvent): void => {
        state.x = evt.clientX - offsetX;
        state.y = evt.clientY - offsetY;
        this.setStyle();
      };

      const onMouseUp = (): void => {
        // 恢复选择文本功能
        document.body.style.userSelect = '';
        document.removeEventListener('mousemove', onMouseMove);
        document.removeEventListener('mouseup', onMouseUp);
      };

      document.addEventListener('mousemove', onMouseMove);
      document.addEventListener('mouseup', onMouseUp);
    };
    // 注册窗口大小变更
    interact(this.containerRef.current!).resizable({
      // 可拖拽的边缘
      edges: {
        top: true,
        right: true,
        bottom: true,
        left: true,
      },
      margin: 6,
      modifiers: [
        // 保持在父对象内部
        interact.modifiers.restrictEdges({ outer: document.body }),
        // 缩放最小宽度
        interact.modifiers.restrictSize({
          min: { width: state.minWidth, height: state.minHeight },
        }),
      ],
      inertia: true,
      listeners: {
        move: event => {
          if (this.state.isFullScreen) return;
          state.x = event.rect.left;
          state.y = event.rect.top;
          // 更新宽高
          state.width = event.rect.width;
          state.height = event.rect.height;
          this.setStyle();
        },
        start: () => {
          // 禁止选择文本，避免拖动时出现选择效果
          this.disabled = true;
          document.body.style.userSelect = 'none';
        },
        end: () => {
          // 恢复选择文本功能
          this.disabled = false;
          document.body.style.userSelect = '';
        },
      },
    });
  }

  componentWillUnmount(): void {
    localStorage.setItem(AIChatConst.STYLE_CACHE, JSON.stringify(this.data));
    localStorage.setItem(
      AIChatConst.MINIMIZE_STYLY_CHCHE,
      JSON.stringify(this.minimizeData),
    );
  }

  /**
   * 关闭聊天窗口
   *
   * @author chitanda
   * @date 2023-10-15 19:10:31
   */
  close(): void {
    this.props.close();
  }

  /**
   * 全屏
   *
   * @author ljx
   * @date 2024-05-07 15:10:31
   */
  fullScreen(): void {
    const container = this.containerRef.current;
    if (container) {
      container.requestFullscreen();
      this.setState({ isFullScreen: true });
      this.props.fullscreen(true);
    }
  }

  /**
   * 关闭全屏
   *
   * @author ljx
   * @date 2024-05-07 15:10:31
   */
  closeFullScreen(): void {
    if (this.state.isFullScreen) {
      document?.exitFullscreen();
      this.setState({ isFullScreen: false });
      this.props.fullscreen(false);
      this.setStyle();
    }
  }

  /**
   * 最小化
   *
   * @memberof ChatContainer
   */
  minimize(): void {
    this.closeFullScreen();
    this.setState({ isMinimize: true });
    this.props.minimize(true);
  }

  /**
   * 退出最小化
   *
   * @memberof ChatContainer
   */
  exitMinimize(): void {
    if (this.isDragging) return;
    this.setState({ isMinimize: false });
    this.props.minimize(false);
  }

  /**
   * 阻止冒泡
   * - 防止点击头部行为时误触发拖动监听
   * @param {MouseEvent} evt
   * @memberof ChatContainer
   */
  stopPropagation(evt: MouseEvent): void {
    evt.stopPropagation();
  }

  render() {
    return (
      <div className={`${this.ns.b()}`}>
        <div
          className={`${this.ns.e('dialog')} ${this.ns.is(
            'full-screen',
            this.state.isFullScreen,
          )} ${this.ns.is('hidden', this.state.isMinimize)}`}
          ref={this.containerRef}
        >
          <div ref={this.dragHandle} className={this.ns.b('header')}>
            <div className={this.ns.b('header-caption')}>
              {this.props.caption || 'AI助手'}
            </div>
            <div className={this.ns.b('header-action-wrapper')}>
              <div
                title='最小化'
                className={`${this.ns.be(
                  'header-action-wrapper',
                  'action-item',
                )} ${this.ns.be('header-action-wrapper', 'minimize')}`}
                onMouseDown={this.stopPropagation.bind(this)}
                onClick={this.minimize.bind(this)}
              >
                <MinimizeSvg />
              </div>
              {this.state.isFullScreen ? (
                <div
                  title='退出全屏'
                  className={`${this.ns.be(
                    'header-action-wrapper',
                    'action-item',
                  )} ${this.ns.be(
                    'header-action-wrapper',
                    'close-full-screen',
                  )}`}
                  onMouseDown={this.stopPropagation.bind(this)}
                  onClick={this.closeFullScreen.bind(this)}
                >
                  <CloseFullScreenSvg />
                </div>
              ) : (
                <div
                  title='全屏'
                  className={`${this.ns.be(
                    'header-action-wrapper',
                    'action-item',
                  )} ${this.ns.be('header-action-wrapper', 'full-screen')}`}
                  onMouseDown={this.stopPropagation.bind(this)}
                  onClick={this.fullScreen.bind(this)}
                >
                  <FullScreenSvg />
                </div>
              )}
              <div
                title='关闭'
                className={`${this.ns.be(
                  'header-action-wrapper',
                  'action-item',
                )} ${this.ns.be('header-action-wrapper', 'action-close')}`}
                onMouseDown={this.stopPropagation.bind(this)}
                onClick={this.close.bind(this)}
              >
                <CloseSvg />
              </div>
            </div>
          </div>
          {this.props.mode === 'TOPIC' ? (
            <div className={`${this.ns.b('main')}`}>
              <div className={`${this.ns.be('main', 'left')}`}>
                <ChatTopics controller={this.props.aiTopic}></ChatTopics>
              </div>
              <div className={`${this.ns.be('main', 'right')}`}>
                <div className={this.ns.b('content')}>
                  <ChatMessages
                    controller={this.props.aiChat}
                    toolbarItems={this.props.contentToolbarItems}
                  />
                </div>
                <ChatToolbar
                  data={{}}
                  type='footer'
                  className={this.ns.e('toolbar')}
                  controller={this.props.aiChat}
                  items={this.props.footerToolbarItems}
                />
                <div className={this.ns.b('footer')}>
                  <ChatInput controller={this.props.aiChat} />
                </div>
              </div>
            </div>
          ) : (
            <div className={`${this.ns.be('main', 'default')}`}>
              <div className={this.ns.b('content')}>
                <ChatMessages
                  controller={this.props.aiChat}
                  toolbarItems={this.props.contentToolbarItems}
                />
              </div>
              <ChatToolbar
                data={{}}
                type='footer'
                className={this.ns.e('toolbar')}
                controller={this.props.aiChat}
                items={this.props.footerToolbarItems}
              />
              <div className={this.ns.b('footer')}>
                <ChatInput controller={this.props.aiChat} />
              </div>
            </div>
          )}
        </div>
        <div
          title='AI助手'
          ref={this.minimizeRef}
          className={`${this.ns.e('minimize')} ${this.ns.is(
            'hidden',
            !this.state.isMinimize,
          )}`}
          onClick={this.exitMinimize.bind(this)}
        >
          <AISvg />
        </div>
      </div>
    );
  }
}
